//package cn.edu.xmu.oomall.customer.dao;
//
//import cn.edu.xmu.oomall.core.util.JacksonUtil;
//import cn.edu.xmu.oomall.core.util.ReturnNo;
//import cn.edu.xmu.oomall.core.util.ReturnObject;
//import cn.edu.xmu.oomall.customer.mapper.CouponPoMapper;
//import cn.edu.xmu.oomall.customer.microservice.CouponActivityService;
//import cn.edu.xmu.oomall.customer.model.bo.Coupon;
//import cn.edu.xmu.oomall.customer.model.po.CouponPo;
//import cn.edu.xmu.oomall.customer.model.po.CouponPoExample;
//import cn.edu.xmu.privilegegateway.annotation.util.RedisUtil;
//import com.github.pagehelper.PageHelper;
//import com.github.pagehelper.PageInfo;
//import org.apache.rocketmq.spring.core.RocketMQTemplate;
//import org.springframework.core.io.ClassPathResource;
//import org.springframework.data.redis.core.script.DefaultRedisScript;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.messaging.support.MessageBuilder;
//import org.springframework.scripting.support.ResourceScriptSource;
//import org.springframework.stereotype.Repository;
//import org.springframework.messaging.Message;
//
//import javax.annotation.Resource;
//import java.util.ArrayList;
//import java.util.List;
//import java.util.stream.Collectors;
//import java.util.stream.Stream;
//
//import static cn.edu.xmu.oomall.core.util.Common.getAvgArray;
//import static cn.edu.xmu.privilegegateway.annotation.util.Common.cloneVo;
//
///**
// * @author XJX
// * @date 2021-12-11 14:56:13
// */
//
//@Repository
//public class CouponDao {
//
//    private static final Logger logger = LoggerFactory.getLogger(CouponDao.class);
//    /**
//     * 活动的优惠券集合,%d值为活动id
//     */
//    private final static String COUPON_SET_KEY = "coupon_%d_set";
//    private final static String COUPON_STOCK_GROUP_KEY = "coupon_%d_stockgroup_%d";
//
//    private final static String LOAD_PATH = "coupon/load.lua";
//    private final static String DECREASE_PATH = "coupon/decrease.lua";
//
//    @Autowired
//    CouponPoMapper couponPoMapper;
//
//    @Autowired
//    CouponActivityService couponActivityService;
//
//    @Resource
//    private RocketMQTemplate rocketMQTemplate;
//
//    @Autowired
//    private RedisUtil redis;
//
//    public ReturnObject getCouponsByExample(CouponPoExample example, Integer page, Integer pageSize) {
//        try {
//            PageHelper.startPage(page, pageSize);
//            List<CouponPo> couponPos = couponPoMapper.selectByExample(example);
//            List<Coupon> coupons = new ArrayList<>();
//            for (CouponPo couponPo : couponPos) {
//                coupons.add(cloneVo(couponPo, Coupon.class));
//            }
//            PageInfo pageInfo = PageInfo.of(couponPos);
//            pageInfo.setList(coupons);
//            return new ReturnObject(pageInfo);
//        } catch (Exception e) {
//            logger.error("getCouponsByExample:error in getCouponsByExample");
//            return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR);
//        }
//    }
//
//    public ReturnObject insertCoupon(Coupon coupon) {
//        try {
//            String json = JacksonUtil.toJson(coupon);
//            Message message = MessageBuilder.withPayload(json).build();
//            rocketMQTemplate.sendOneWay("coupon-topic", message);
//            return new ReturnObject();
//        } catch (Exception e) {
//            e.printStackTrace();
//            return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR, e.getMessage());
//        }
//    }
//
//    /**
//     * 减少优惠券的库存
//     *
//     * @param actId         活动id
//     * @param groupNum      将优惠券总数分为多少组
//     * @param quantity      领取的数,一般为1
//     * @param wholeQuantity 优惠券总数
//     * @return 领取结果
//     */
//    public ReturnObject decreaseCouponQuantity(Long actId, Integer groupNum, Integer quantity, Integer wholeQuantity) {
//        try {
//            String setKey = String.format(COUPON_SET_KEY, actId);
//            if (!redis.hasKey(setKey)) {
//                loadQuantity(setKey, actId, groupNum, wholeQuantity);
//            }
//
//            DefaultRedisScript<Long> script = new DefaultRedisScript<>();
//            script.setScriptSource(new ResourceScriptSource(new ClassPathResource(DECREASE_PATH)));
//            script.setResultType(Long.class);
//
//            long timeSeed = System.currentTimeMillis();
//            Long res = redis.executeScript(script, Stream.of(setKey).collect(Collectors.toList()), quantity, timeSeed);
//
//            if (res >= 0) {
//                return new ReturnObject(ReturnNo.OK);
//            }
//            return new ReturnObject(ReturnNo.COUPON_FINISH, "领取优惠券失败");
//        } catch (Exception e) {
//            logger.error(e.getMessage());
//            return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR, e.getMessage());
//        }
//    }
//
//    /**
//     * 将优惠券数量加载进redis并且分为若干个桶
//     *
//     * @param setKey        集合Key
//     * @param id            活动id
//     * @param groupNum      分为桶的个数
//     * @param wholeQuantity 优惠券总数
//     */
//    private void loadQuantity(String setKey, Long id, Integer groupNum, Integer wholeQuantity) {
//        /**
//         *  COUPON_SET_KEY 1--* COUPON_STOCK_GROUP_KEY 1--1 STOCK
//         */
//        int[] incr = getAvgArray(groupNum, wholeQuantity);
//        DefaultRedisScript script = new DefaultRedisScript<>();
//        script.setScriptSource(new ResourceScriptSource(new ClassPathResource(LOAD_PATH)));
//
//        for (int i = 0; i < groupNum; i++) {
//            redis.executeScript(script, Stream.of(setKey, String.format(COUPON_STOCK_GROUP_KEY, id, i)).collect(Collectors.toList()), incr[i]);
//        }
//    }
//}
package cn.edu.xmu.oomall.customer.dao;

import cn.edu.xmu.oomall.core.util.JacksonUtil;
import cn.edu.xmu.oomall.core.util.ReturnNo;
import cn.edu.xmu.oomall.core.util.ReturnObject;
import cn.edu.xmu.oomall.customer.mapper.CouponPoMapper;
import cn.edu.xmu.oomall.customer.microservice.CouponActivityService;
import cn.edu.xmu.oomall.customer.model.bo.Coupon;
import cn.edu.xmu.oomall.customer.model.po.CouponPo;
import cn.edu.xmu.oomall.customer.model.po.CouponPoExample;
import cn.edu.xmu.privilegegateway.annotation.util.RedisUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Repository;
import org.springframework.messaging.Message;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.edu.xmu.oomall.core.util.Common.getAvgArray;
import static cn.edu.xmu.privilegegateway.annotation.util.Common.cloneVo;

/**
 * @author XJX
 * @date 2021-12-11 14:56:13
 */

@Repository
public class CouponDao implements InitializingBean {

    private static final Logger logger = LoggerFactory.getLogger(CouponDao.class);
    /**
     * 活动的优惠券集合,%d值为活动id
     */
    private final static String COUPON_SET_KEY = "coupon_%d_set";
    private final static String COUPON_STOCK_GROUP_KEY = "coupon_%d_stockgroup_%d";

    private final static String LOAD_PATH = "coupon/load.lua";
    private final static String DECREASE_PATH = "coupon/decrease.lua";

    @Autowired
    CouponPoMapper couponPoMapper;

    @Autowired
    CouponActivityService couponActivityService;

    @Resource
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private RedisUtil redis;

    private static  DefaultRedisScript<Long> script = null;

    @Override
    public void afterPropertiesSet() throws Exception {
        script = new DefaultRedisScript<>();
        script.setScriptSource(new ResourceScriptSource(new ClassPathResource(DECREASE_PATH)));
        script.setResultType(Long.class);
    }

    public ReturnObject getCouponsByExample(CouponPoExample example, Integer page, Integer pageSize) {
        try {
            PageHelper.startPage(page, pageSize);
            List<CouponPo> couponPos = couponPoMapper.selectByExample(example);
            List<Coupon> coupons = new ArrayList<>();
            for (CouponPo couponPo : couponPos) {
                coupons.add(cloneVo(couponPo, Coupon.class));
            }
            PageInfo pageInfo = PageInfo.of(couponPos);
            pageInfo.setList(coupons);
            return new ReturnObject(pageInfo);
        } catch (Exception e) {
            logger.error("getCouponsByExample:error in getCouponsByExample");
            return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR);
        }
    }

    public ReturnObject insertCoupon(Coupon coupon) {
        try {
            String json = JacksonUtil.toJson(coupon);
            Message message = MessageBuilder.withPayload(json).build();
            rocketMQTemplate.sendOneWay("coupon-topic", message);
            return new ReturnObject();
        } catch (Exception e) {
            e.printStackTrace();
            return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR, e.getMessage());
        }
    }

    /**
     * 减少优惠券的库存
     *
     * @param actId         活动id
     * @param groupNum      将优惠券总数分为多少组
     * @param quantity      领取的数,一般为1
     * @param wholeQuantity 优惠券总数
     * @return 领取结果
     */
    public ReturnObject decreaseCouponQuantity(Long actId, Integer groupNum, Integer quantity, Integer wholeQuantity) {
        try {
            String setKey = String.format(COUPON_SET_KEY, actId);
            if (!redis.hasKey(setKey)) {
                loadQuantity(setKey, actId, groupNum, wholeQuantity);
            }

            long timeSeed = System.currentTimeMillis();
            Long res = redis.executeScript(script, Stream.of(setKey).collect(Collectors.toList()), quantity, timeSeed);

            if (res >= 0) {
                return new ReturnObject(ReturnNo.OK);
            }
            return new ReturnObject(ReturnNo.COUPON_FINISH, "领取优惠券失败");
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR, e.getMessage());
        }
    }

    /**
     * 将优惠券数量加载进redis并且分为若干个桶
     *
     * @param setKey        集合Key
     * @param id            活动id
     * @param groupNum      分为桶的个数
     * @param wholeQuantity 优惠券总数
     */
    private void loadQuantity(String setKey, Long id, Integer groupNum, Integer wholeQuantity) {
        /**
         *  COUPON_SET_KEY 1--* COUPON_STOCK_GROUP_KEY 1--1 STOCK
         */
        int[] incr = getAvgArray(groupNum, wholeQuantity);
        DefaultRedisScript script = new DefaultRedisScript<>();
        script.setScriptSource(new ResourceScriptSource(new ClassPathResource(LOAD_PATH)));

        for (int i = 0; i < groupNum; i++) {
            redis.executeScript(script, Stream.of(setKey, String.format(COUPON_STOCK_GROUP_KEY, id, i)).collect(Collectors.toList()), incr[i]);
        }
    }
}